在 IIS 上安装 URL Rewrite 配置 Web API
Configuring Web API with URL Rewrite installed on IIS
我们有一个使用 ASP.Net URL Rewrite 2.0 的 Web 窗体应用程序。以下重写规则配置为允许访问某些页面而不指定 .ashx
扩展名:
<rule name="RewriteASHX">
<match url="(customers|orders|products.*)"/>
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
</conditions>
<action type="Rewrite" url="{R:1}.ashx"/>
</rule>
使用 Web API,我们希望逐渐用 Web API 控制器替换基于 Web 窗体的 API 页面。安装 URL Rewrite 后,只有符合上述规则的控制器才能正确路由到 Web API 控制器。 (向 URL 重写规则添加排除项似乎根本不会让请求到达控制器,从而给出 404 结果。)
Web API 控制器按以下方式设置:
public class CustomersController : ApiController
{
[Route("api/v2/customers")]
[ResponseType(typeof(CustomerCollection))]
public IHttpActionResult Get()
{
...
}
[Route("api/v2/customers/{identifier}")]
[ResponseType(typeof(Customer))]
public IHttpActionResult Get(string identifier)
{
...
}
}
如上所述,如果 Web API 请求与 URL 重写条件匹配,我们只能让它们进行路由。
The parameterless api/v2/customers
in CustomerController
works because it matches <match url="(customers|orders|products.*)"/>
, but api/v2/customers/C123
fails because it does not match the rewrite condition.
配置 URL 重写以允许 Web API 请求正确路由的最佳方法是什么?
URL Rewrite 模块基本上有两个不同的功能:
- 重写传入的 URL 以使其 "look" 像另一个 URL 到 Web 服务器
- 将传入的 URL 重定向到另一个 URL
由于引入了 .NET 路由(用于 ASP.NET、ASP.NET MVC 和 Web API),URL 重写在很大程度上是不必要的。路由要好得多。通过路由,传入请求被准确地发送到目标控制器方法。通过重写,HTTP 上下文被重写以欺骗 ASP.NET 将请求发送到其他地方,这可能会导致依赖 HTTP 上下文值工作的事物出现问题。
另一方面,重定向对于 URL 重写仍然非常有用。特别是当涉及到您正在升级的旧应用程序中的遗留 URLs 时。为确保所有旧 URL 都能正常工作(并且不损害搜索引擎排名),请使用 301 重定向。 301 重定向 以及 URL 重写。
因此,我的建议是从 URL 切换到路由,为您的所有 "rewrites" 重写,因为路由,它们不再是真正必要的。您可以设置一个类似于您的重写的 configuration with routing 以到达您的 .ashx
页面。
routes.MapPageRoute(
routeName: "RouteASHX",
routeUrl: "{ashxPage}",
physicalFile: "~/{ashxPage}.ashx",
checkPhysicalUrlAccess: false,
defaults: new RouteValueDictionary(),
constraints: new RouteValueDictionary(new { ashxPage = @"customers|orders|products.*" }));
we have only been able to get Web API requests to route if they match a URL Rewrite condition (e.g., the parameterless api/v2/customers
in CustomerController
works because it matches <match url="(customers|orders|products.*)"/>
, but api/v2/customers/C123
fails because it does not match the rewrite condition).
这是另一个不相关的问题,这是由于使用具有相似路径和未定义顺序的属性路由。属性路由的一个问题是 .NET 属性根据定义具有未定义的顺序。另一方面,路由设置是 。这两个目标是矛盾的,这就是你被咬的地方。请参见 属性与传统路由
了解详情。
幸运的是,修复起来并不难。有一个 Order
属性,您可以将其设置为手动覆盖应用 .NET 属性的任意顺序,将更具体的路由放在不太具体的路由之前。
public class CustomersController : ApiController
{
[Route("api/v2/customers", Order = 2)]
[ResponseType(typeof(CustomerCollection))]
public IHttpActionResult Get()
{
...
}
[Route("api/v2/customers/{identifier}", Order = 1)]
[ResponseType(typeof(Customer))]
public IHttpActionResult Get(string identifier)
{
...
}
}
应用此配置将使您的 Web API 工作而无需 URL 重写。
如果您确定您的 Web API 项目只会处理对 "api/v2/..." 的传入请求,那么您可以在顶部写一个新规则来打破,
<rule name="break" stopProcessing="true">
<match url="^api/v2/(.*)" />
<action type="None" />
</rule>
可以在 my blog post 中找到更多详细信息。
我们有一个使用 ASP.Net URL Rewrite 2.0 的 Web 窗体应用程序。以下重写规则配置为允许访问某些页面而不指定 .ashx
扩展名:
<rule name="RewriteASHX">
<match url="(customers|orders|products.*)"/>
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
</conditions>
<action type="Rewrite" url="{R:1}.ashx"/>
</rule>
使用 Web API,我们希望逐渐用 Web API 控制器替换基于 Web 窗体的 API 页面。安装 URL Rewrite 后,只有符合上述规则的控制器才能正确路由到 Web API 控制器。 (向 URL 重写规则添加排除项似乎根本不会让请求到达控制器,从而给出 404 结果。)
Web API 控制器按以下方式设置:
public class CustomersController : ApiController
{
[Route("api/v2/customers")]
[ResponseType(typeof(CustomerCollection))]
public IHttpActionResult Get()
{
...
}
[Route("api/v2/customers/{identifier}")]
[ResponseType(typeof(Customer))]
public IHttpActionResult Get(string identifier)
{
...
}
}
如上所述,如果 Web API 请求与 URL 重写条件匹配,我们只能让它们进行路由。
The parameterless
api/v2/customers
inCustomerController
works because it matches<match url="(customers|orders|products.*)"/>
, butapi/v2/customers/C123
fails because it does not match the rewrite condition.
配置 URL 重写以允许 Web API 请求正确路由的最佳方法是什么?
URL Rewrite 模块基本上有两个不同的功能:
- 重写传入的 URL 以使其 "look" 像另一个 URL 到 Web 服务器
- 将传入的 URL 重定向到另一个 URL
由于引入了 .NET 路由(用于 ASP.NET、ASP.NET MVC 和 Web API),URL 重写在很大程度上是不必要的。路由要好得多。通过路由,传入请求被准确地发送到目标控制器方法。通过重写,HTTP 上下文被重写以欺骗 ASP.NET 将请求发送到其他地方,这可能会导致依赖 HTTP 上下文值工作的事物出现问题。
另一方面,重定向对于 URL 重写仍然非常有用。特别是当涉及到您正在升级的旧应用程序中的遗留 URLs 时。为确保所有旧 URL 都能正常工作(并且不损害搜索引擎排名),请使用 301 重定向。 301 重定向
因此,我的建议是从 URL 切换到路由,为您的所有 "rewrites" 重写,因为路由,它们不再是真正必要的。您可以设置一个类似于您的重写的 configuration with routing 以到达您的 .ashx
页面。
routes.MapPageRoute(
routeName: "RouteASHX",
routeUrl: "{ashxPage}",
physicalFile: "~/{ashxPage}.ashx",
checkPhysicalUrlAccess: false,
defaults: new RouteValueDictionary(),
constraints: new RouteValueDictionary(new { ashxPage = @"customers|orders|products.*" }));
we have only been able to get Web API requests to route if they match a URL Rewrite condition (e.g., the parameterless
api/v2/customers
inCustomerController
works because it matches<match url="(customers|orders|products.*)"/>
, butapi/v2/customers/C123
fails because it does not match the rewrite condition).
这是另一个不相关的问题,这是由于使用具有相似路径和未定义顺序的属性路由。属性路由的一个问题是 .NET 属性根据定义具有未定义的顺序。另一方面,路由设置是
幸运的是,修复起来并不难。有一个 Order
属性,您可以将其设置为手动覆盖应用 .NET 属性的任意顺序,将更具体的路由放在不太具体的路由之前。
public class CustomersController : ApiController
{
[Route("api/v2/customers", Order = 2)]
[ResponseType(typeof(CustomerCollection))]
public IHttpActionResult Get()
{
...
}
[Route("api/v2/customers/{identifier}", Order = 1)]
[ResponseType(typeof(Customer))]
public IHttpActionResult Get(string identifier)
{
...
}
}
应用此配置将使您的 Web API 工作而无需 URL 重写。
如果您确定您的 Web API 项目只会处理对 "api/v2/..." 的传入请求,那么您可以在顶部写一个新规则来打破,
<rule name="break" stopProcessing="true">
<match url="^api/v2/(.*)" />
<action type="None" />
</rule>
可以在 my blog post 中找到更多详细信息。